package com.zazu.mycl.application.commands;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
import java.util.logging.Level;

import com.zazu.mycl.application.ApplicationController;
import com.zazu.mycl.application.CommandRunner;
import com.zazu.mycl.application.terminalCommand;

public class TelnetCommand implements terminalCommand {

	public String getSignature() {
		// TODO Auto-generated method stub
		return "[hostName] [Port]";
	}

	public boolean isThreadable() {
		// TODO Auto-generated method stub
		return true;
	}

	public void run(String[] args, CommandRunner commandRunner,
			String commandLine, String outputFileName) {
	
		this.commandRunner = commandRunner;
		
		commandRunner.TakeControll(this);
		commandRunner.SetLine("Running telnet.");
		
		
		if(args.length >= 3)
		{
			int portInt = new Integer(args[2]).intValue();
			this.setConnection(args[1],portInt);
			out.flush();
			commandRunner.SetLine(in.nextLine());
		}
		else
		{
			commandRunner.SetLine("Type in ? for help.");
		}
		
	}

	private void setConnection(String host, int port)
	{
		
		ApplicationController.logger.log(Level.INFO, "Entering setConnection.");
		commandRunner.SetLine("Connecting to "+host+"...");
		
		try
		{
			ApplicationController.logger.log(Level.INFO, "Trying to set connection.");
			this.socket = new Socket(host, port);
			socket.setSoTimeout(20000);
			
				OutputStream oStream = socket.getOutputStream();
				
				this.out = new PrintWriter(oStream, true /* autoflush */);
				
				ApplicationController.logger.log(Level.INFO, "Got input stream.");
				
				InputStream iStream =  socket.getInputStream();
				this.in = new Scanner(iStream);
				
				ApplicationController.logger.log(Level.INFO, "Got output stream.");
				
				commandRunner.SetLine("Connected to "+host+".");
				
				ApplicationController.logger.log(Level.INFO, "Waiting for message.");
				
				/*
					if(socket.isConnected())
					{
						while(this.in.hasNextLine())
						{
							commandRunner.SetLine(this.in.nextLine());
							this.out.flush();
						}
					}
				*/
				
		}
		catch(IOException e)
		{
			commandRunner.SetLine("Error establishing connection with server.");
		}
		catch(Exception e)
		{
			commandRunner.SetLine("Error opening connection.");
		}
	}
	
	private void shutdown()
	{
		commandRunner.SetLine("Exiting telnet...");
		
		try {
			socket.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		finally
		{
			commandRunner.RelinqishControll();
		}
		
		return;
	}
	
	
	
	public void runSubCommand(String[] args, String commandLine) {
		
		if(commandLine.equals("q"))
		{
			this.shutdown();
		}
		else if(commandLine.equals("lh"))
		{
			//Get localhost
			InetAddress localHost;
			try {
				localHost = Inet6Address.getLocalHost();
				commandRunner.SetLine("Local host info...");
				commandRunner.SetLine("Host address: "+localHost.getHostAddress());
				commandRunner.SetLine("Host name: "+localHost.getHostName());
				commandRunner.SetLine("Host name: "+localHost.getCanonicalHostName());
				commandRunner.SetLine("Is Loopback: "+localHost.isLoopbackAddress());
				commandRunner.SetLine("");
				
				InetAddress[] inets = localHost.getAllByName(localHost.getHostName());
				
				for(InetAddress inad : inets)
				{
					commandRunner.SetLine("Additional Host:");
					commandRunner.SetLine("\tHost address: "+localHost.getHostAddress());
					commandRunner.SetLine("\tHost name: "+localHost.getHostName());
					commandRunner.SetLine("\tHost name: "+localHost.getCanonicalHostName());
					commandRunner.SetLine("\tIs Loopback: "+localHost.isLoopbackAddress());
					commandRunner.SetLine("");
				}
				
			} catch (UnknownHostException e) {
				commandRunner.SetLine("Error getting localhost information.");
			}
			
			
		}
		else if(commandLine.startsWith("c"))
		{
			if(socket != null)
			{
				try {
					socket.close();
					socket = null;
					commandRunner.SetLine("Socket closed.");
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		else if(commandLine.startsWith("o"))
		{
			if(args.length >= 3)
			{
				int portInt = new Integer(args[2]).intValue();
				ApplicationController.logger.log(Level.INFO, "Attempting to set telnet connection.");
				setConnection(args[1],portInt);
			}
			else
			{
				commandRunner.SetLine("Insufficient parameters. Parameters: "+this.getSignature());
			}
		}
		//Start output buffer
		else if(commandLine.startsWith("sob"))
		{
			sob = true;
		}
		//End output buffer
		else if(commandLine.startsWith("eob"))
		{
			out.println(this.OutputBuffer);
			
			//Empty the buffer
			this.OutputBuffer.delete(0, this.OutputBuffer.length());
			commandRunner.SetLine(in.nextLine());
			sob = false;
		}
		else if(commandLine.startsWith("sen"))
		{
			String clientCommand = commandLine.substring(4,commandLine.length()); 
			
			try
			{	
				out.println(clientCommand);
				
				commandRunner.SetLine(in.nextLine());
				
			}
			catch(Exception e)
			{
				//commandRunner.SetLine("Error communicating with telnet.");
				//shutdown();
			}
		}
		else if(commandLine.startsWith("st"))
		{
			if(socket == null)
			{
				commandRunner.SetLine("Not connected to any host.");
			}
			else if(socket.isConnected())
			{
				commandRunner.SetLine("Connected to "+socket.getInetAddress().getCanonicalHostName());
			}
			else if(!socket.isConnected())
			{
				commandRunner.SetLine("Current host"+socket.getInetAddress().getCanonicalHostName()+" not connected.");
			}
			
		}
		else if(sob == true)
		{
			this.OutputBuffer.append(commandLine+"\n");
		}
		else if(commandLine.startsWith("?"))
		{
			StringBuilder sb = new StringBuilder();
			
			sb.append("q: quit telnet.\n");
			sb.append("lh: get localhost info.\n");
			sb.append("o [HostName] [Port]: Open a connection.\n");
			sb.append("sob: Start output buffering.(for sending multiple lines.)\n");
			sb.append("eob: Ends output buffering and sends the contents.\n");
			sb.append("sen: Sends the line to the connection.\n");
			sb.append("st: shows the status of the connection.");
			
			commandRunner.SetLine(sb.toString());
		}
		else
		{
			commandRunner.SetLine("Command not recognized.");
		}
	}

	boolean sob = false;
	StringBuilder OutputBuffer = new StringBuilder();
	Scanner in;
	PrintWriter out;
	Socket socket;
	private CommandRunner commandRunner;
}
